﻿
// InjectDlg.cpp: 实现文件
//

#include "pch.h"
#include "InjectDll.h"
#include "InjectDlg.h"
#include <Tlhelp32.h>
#include "GamePath.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// 用于应用程序“关于”菜单项的 caboutdlg 对话框
// CInjectDLLDlg 对话框

CInjectDLLDlg::CInjectDLLDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_MYMFC_DIALOG, pParent)
{

}

void CInjectDLLDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CInjectDLLDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON1, &CInjectDLLDlg::OnBnClickedButton1)
	ON_BN_CLICKED(IDC_BUTTON2, &CInjectDLLDlg::OnBnClickedButton2)
	ON_BN_CLICKED(IDC_BUTTON3, &CInjectDLLDlg::OnBnClickedButton3)
END_MESSAGE_MAP()

void CInjectDLLDlg::OnBnClickedButton1()
{
	HANDLE g_hThread = NULL;
	// TODO: 在此添加控件通知处理程序代码
	g_hThread = CreateThread(NULL, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(LoadLibrary), (LPVOID)dllPath, 0, 0);
	if (NULL == g_hThread)
	{
		MessageBox(L"加载 Wgdll.dll 失败");
	}
	else if (g_hThread)
	{
		CloseHandle(g_hThread);
	}
}

bool FindDll(const TCHAR* ptszDllFile, DWORD dwProcessId, MODULEENTRY32* pme32)
{
	HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
	// 获取模块快照   
	hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
	if (INVALID_HANDLE_VALUE == hModuleSnap)
	{
		return false;
	}

	memset(pme32, 0, sizeof(MODULEENTRY32));
	pme32->dwSize = sizeof(MODULEENTRY32);

	// 开始遍历   
	if (FALSE == ::Module32First(hModuleSnap, pme32))
	{
		CloseHandle(hModuleSnap);
		return false;
	}
	// 遍历查找指定模块   
	bool isFound = false;
	do
	{
		isFound = (0 == _tcsicmp(pme32->szModule, ptszDllFile) || 0 == _tcsicmp(pme32->szExePath, ptszDllFile));
		if (isFound) // 找到指定模块   
		{
			break;
		}
	} while (TRUE == Module32Next(hModuleSnap, pme32));

	CloseHandle(hModuleSnap);

	if (false == isFound)
	{
		return false;
	}
	return true;
}


//-----------------------------------------------------------------------------------------------------------   
// 函数: InjectDll   
// 功能: 向目标进程中注入一个指定 Dll 模块文件.   
// 参数: [in] const TCHAR* ptszDllFile - Dll 文件名及路径   
//       [in] DWORD dwProcessId - 目标进程 ID   
// 返回: bool - 注入成功返回 true, 注入失败则返回 false.   
// 说明: 采用远程线程注入技术实现   
//-----------------------------------------------------------------------------------------------------------   
bool InjectDll(const TCHAR* ptszDllFile, DWORD dwProcessId)
{
	// 参数无效   
	if (NULL == ptszDllFile || 0 == ::_tcslen(ptszDllFile))
	{
		return false;
	}
	// 指定 Dll 文件不存在   
	if (-1 == _taccess(ptszDllFile, 0))
	{
		return false;
	}

	MODULEENTRY32 me32;
	if (FindDll(ptszDllFile, dwProcessId, &me32))
	{
		AfxMessageBox(__T("Wgdll.dll 已经存在"));
		return false;
	}

	HANDLE hProcess = NULL;
	HANDLE hThread = NULL;
	DWORD dwSize = 0;
	TCHAR* ptszRemoteBuf = NULL;
	LPTHREAD_START_ROUTINE lpThreadFun = NULL;

	// 获取目标进程句柄   
	hProcess = ::OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, dwProcessId);
	if (NULL == hProcess)
	{
		return false;
	}
	// 在目标进程中分配内存空间
	dwSize = (DWORD)::_tcslen(ptszDllFile) + 1;
	ptszRemoteBuf = (TCHAR*)::VirtualAllocEx(hProcess, NULL, dwSize * sizeof(TCHAR), MEM_COMMIT, PAGE_READWRITE);
	if (NULL == ptszRemoteBuf)
	{
		::CloseHandle(hProcess);
		return false;
	}
	// 在目标进程的内存空间中写入所需参数(模块名)
	if (FALSE == ::WriteProcessMemory(hProcess, ptszRemoteBuf, (LPVOID)ptszDllFile, dwSize * sizeof(TCHAR), NULL))
	{
		::VirtualFreeEx(hProcess, ptszRemoteBuf, 0, MEM_RELEASE);
		::CloseHandle(hProcess);
		return false;
	}
	// 从 Kernel32.dll 中获取 LoadLibrary 函数地址   
#ifdef _UNICODE   
	lpThreadFun = (PTHREAD_START_ROUTINE)::GetProcAddress(_Notnull_::GetModuleHandle(_T("Kernel32")), "LoadLibraryW");
#else   
	lpThreadFun = (PTHREAD_START_ROUTINE)::GetProcAddress(_Notnull_::GetModuleHandle(_T("Kernel32")), "LoadLibraryA");
#endif   
	if (NULL == lpThreadFun)
	{
		::VirtualFreeEx(hProcess, ptszRemoteBuf, 0, MEM_RELEASE);
		::CloseHandle(hProcess);
		return false;
	}
	// 创建远程线程调用 LoadLibrary   
	hThread = ::CreateRemoteThread(hProcess, NULL, 0, lpThreadFun, ptszRemoteBuf, 0, NULL);
	if (NULL == hThread)
	{
		::VirtualFreeEx(hProcess, ptszRemoteBuf, 0, MEM_RELEASE);
		::CloseHandle(hProcess);
		return false;
	}
	// 等待远程线程结束   
	::WaitForSingleObject(hThread, INFINITE);
	// 清理   
	::VirtualFreeEx(hProcess, ptszRemoteBuf, 0, MEM_RELEASE);
	::CloseHandle(hThread);
	::CloseHandle(hProcess);
	return true;
}
//-----------------------------------------------------------------------------------------------------------   
// 函数: UnInjectDll   
// 功能: 从目标进程中卸载一个指定 Dll 模块文件.   
// 参数: [in] const TCHAR* ptszDllFile - Dll 文件名及路径   
//       [in] DWORD dwProcessId - 目标进程 ID   
// 返回: bool - 卸载成功返回 true, 卸载失败则返回 false.   
// 说明: 采用远程线程注入技术实现   
//-----------------------------------------------------------------------------------------------------------   
bool UnInjectDll(const TCHAR* ptszDllFile, DWORD dwProcessId)
{
	// 参数无效   
	if (NULL == ptszDllFile || 0 == ::_tcslen(ptszDllFile))
	{
		return false;
	}
	HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
	HANDLE hProcess = NULL;
	HANDLE hThread = NULL;

	MODULEENTRY32 me32;
	if (!FindDll(ptszDllFile, dwProcessId, &me32))
	{
		AfxMessageBox(__T("Wgdll.dll 不存在"));
		return false;
	}

	// 获取目标进程句柄   
	hProcess = ::OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION, FALSE, dwProcessId);
	if (NULL == hProcess)
	{
		return false;
	}
	// 从 Kernel32.dll 中获取 FreeLibrary 函数地址   
	LPTHREAD_START_ROUTINE lpThreadFun = (PTHREAD_START_ROUTINE)::GetProcAddress(::GetModuleHandle(_T("Kernel32")), "FreeLibrary");
	if (NULL == lpThreadFun)
	{
		::CloseHandle(hProcess);
		return false;
	}
	// 创建远程线程调用 FreeLibrary   
	hThread = ::CreateRemoteThread(hProcess, NULL, 0, lpThreadFun, me32.modBaseAddr /* 模块地址 */, 0, NULL);
	if (NULL == hThread)
	{
		::CloseHandle(hProcess);
		return false;
	}
	// 等待远程线程结束   
	::WaitForSingleObject(hThread, INFINITE);
	// 清理   
	::CloseHandle(hThread);
	::CloseHandle(hProcess);
	return true;
}


BOOL getProcess32Info(PROCESSENTRY32* info, const TCHAR processName[])
{
	HANDLE handle; //定义CreateToolhelp32Snapshot系统快照句柄
	handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);//获得系统快照句柄
	//PROCESSENTRY32 结构的 dwSize 成员设置成 sizeof(PROCESSENTRY32)
	info->dwSize = sizeof(PROCESSENTRY32);
	//调用一次 Process32First 函数，从快照中获取进程列表
	Process32First(handle, info);
	//重复调用 Process32Next，直到函数返回 FALSE 为止
	while (Process32Next(handle, info) != FALSE)
	{
		if (wcscmp(processName, info->szExeFile) == 0)
		{
			return TRUE;
		}
	}
	return FALSE;
}


BOOL EnableDebugPrivilege()
{
	HANDLE hToken;
	BOOL fOk = FALSE;
	if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
	{
		TOKEN_PRIVILEGES tp;
		tp.PrivilegeCount = 1;
		LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
		tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

		AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);

		fOk = (GetLastError() == ERROR_SUCCESS);
		CloseHandle(hToken);
	}
	return fOk;
}

BOOL ZwCreateThreadExInjectDll(DWORD dwProcessId, const TCHAR* pszDllFileName)
{
	// 参数无效   
	if (NULL == pszDllFileName || 0 == ::_tcslen(pszDllFileName))
	{
		return false;
	}
	// 指定 Dll 文件不存在   
	if (-1 == _taccess(pszDllFileName, 0))
	{
		return false;
	}
	if (!EnableDebugPrivilege())
		return FALSE;

	size_t pathSize = (_tcsclen(pszDllFileName) + 1) * sizeof(TCHAR);
	// 1.打开目标进程
	HANDLE hProcess = OpenProcess(
		PROCESS_ALL_ACCESS, // 打开权限
		FALSE, // 是否继承
		dwProcessId); // 进程PID
	if (NULL == hProcess)
	{
		MessageBox(NULL, __T("打开目标进程失败！"), NULL, MB_OK);
		return FALSE;
	}
	// 2.在目标进程中申请空间
	LPVOID lpPathAddr = VirtualAllocEx(
		hProcess, // 目标进程句柄
		0, // 指定申请地址
		pathSize, // 申请空间大小
		MEM_RESERVE | MEM_COMMIT, // 内存的状态
		PAGE_READWRITE); // 内存属性
	if (NULL == lpPathAddr)
	{
		MessageBox(NULL, __T("在目标进程中申请空间失败"), NULL, MB_OK);
		CloseHandle(hProcess);
		return FALSE;
	}
	// 3.在目标进程中写入Dll路径
	if (FALSE == WriteProcessMemory(
		hProcess, // 目标进程句柄
		lpPathAddr, // 目标进程地址
		pszDllFileName, // 写入的缓冲区
		pathSize, // 缓冲区大小
		NULL)) // 实际写入大小
	{
		MessageBox(NULL, __T("目标进程中写入Dll路径失败！"), NULL, MB_OK);
		CloseHandle(hProcess);
		return FALSE;
	}

	//4.加载ntdll.dll
	HMODULE hNtdll = LoadLibrary(L"ntdll.dll");
	if (NULL == hNtdll)
	{
		MessageBox(NULL, __T("加载ntdll.dll失败！"), NULL, MB_OK);
		CloseHandle(hProcess);
		return FALSE;
	}

	//5.获取LoadLibraryA的函数地址
	//FARPROC可以自适应32位与64位
	FARPROC pFuncProcAddr;
#ifdef _UNICODE   
	pFuncProcAddr = ::GetProcAddress(::GetModuleHandle(_T("Kernel32")), "LoadLibraryW");
#else   
	pFuncProcAddr = ::GetProcAddress(::GetModuleHandle(_T("Kernel32")), "LoadLibraryA");
#endif   
	//FARPROC pFuncProcAddr = :: GetProcAddress(GetModuleHandle(L"Kernel32.dll"), "LoadLibraryW");
	if (NULL == pFuncProcAddr)
	{
		AfxMessageBox(__T("获取LoadLibrary函数地址失败！"));
		CloseHandle(hProcess);
		return FALSE;
	}

	//6.获取ZwCreateThreadEx函数地址,该函数在32位与64位下原型不同
	//_WIN64用来判断编译环境 ，_WIN32用来判断是否是Windows系统

	typedef_ZwCreateThreadEx ZwCreateThreadEx = (typedef_ZwCreateThreadEx)GetProcAddress(hNtdll, "ZwCreateThreadEx");
	if (NULL == ZwCreateThreadEx)
	{
		AfxMessageBox(__T("获取ZwCreateThreadEx函数地址失败！"));
		CloseHandle(hProcess);
		return FALSE;
	}
	//7.在目标进程中创建远线程
	HANDLE hRemoteThread = NULL;
	DWORD dwStatus = ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, hProcess,
		(LPTHREAD_START_ROUTINE)pFuncProcAddr, lpPathAddr, 0, 0, 0, 0, NULL);
	if (NULL == hRemoteThread)
	{
		AfxMessageBox(__T("目标进程中创建线程失败！"));
		CloseHandle(hProcess);
		return FALSE;
	}


	// 8.等待线程结束
	WaitForSingleObject(hRemoteThread, INFINITE);
	// 9.清理环境
	VirtualFreeEx(hProcess, lpPathAddr, 0, MEM_RELEASE);
	CloseHandle(hRemoteThread);
	CloseHandle(hProcess);
	FreeLibrary(hNtdll);
	return TRUE;
}


void GetDllAllPath(CString* str, const TCHAR* path)
{
	TCHAR szPath[MAX_PATH];
	UINT pos;
	UINT len;
	GetModuleFileName(NULL, szPath, MAX_PATH);
	*str = szPath;
	pos = str->ReverseFind('\\');
	len = str->GetLength() - pos;
	str->Delete(pos + 1, len);
	str->Append(path);
}


void CInjectDLLDlg::OnBnClickedButton2()
{
	CString str;
	bool okret = false;
	// TODO: 在此添加控件通知处理程序代码
	PROCESSENTRY32 info;
	// 查找指定进程名的PID
	if (getProcess32Info(&info, exePath))
	{
		GetDllAllPath(&str, dllPath);

		// 进程标识符PID。
		okret = InjectDll(str.GetString(), info.th32ProcessID);
		//okret = ZwCreateThreadExInjectDll(info.th32ProcessID, str.GetString());
	}
}


void CInjectDLLDlg::OnBnClickedButton3()
{
	// TODO: 在此添加控件通知处理程序代码
	CString str;
	bool okret = false;
	// TODO: 在此添加控件通知处理程序代码
	PROCESSENTRY32 info;
	// 查找指定进程名的PID
	if (getProcess32Info(&info, exePath))
	{
		GetDllAllPath(&str, dllPath);
		// 进程标识符PID。
		okret = UnInjectDll(str.GetString(), info.th32ProcessID);
		//okret = ZwCreateThreadExInjectDll(info.th32ProcessID, str.GetString());
	}
}
